home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / trunk.zip / TRUNK.C < prev    next >
C/C++ Source or Header  |  1993-01-04  |  10KB  |  307 lines

  1. /* QuickC source for TRUNK */
  2. /***************************************************************************/
  3. /***************************************************************************/
  4. /**
  5. *** TRUNK -- a replacement for the MS-DOS 'TREE' command.  TREE allows only
  6. *** one option ('/F'--similar to the one implemented in TRUNK), but more
  7. *** to the point, the output is verbose and completely unsuited for passing
  8. *** to other programs.  TRUNK is fully redirectable using MS-DOS redirection
  9. *** and pipes.
  10. ***
  11. *** Command line option flags are evaluated in left-to-right order.
  12. *** Flags may conflict with each other, and the flag to the right takes
  13. *** precedence--e.g. the command line 'TRUNK /F /o' will print only a
  14. *** summary, no file names.
  15. ***
  16. *** Enjoy.
  17. ***
  18. *** Official TRUNK soundtrack:
  19. *** "Fleetwood Mac in Chicago"  Sire: SASH 3175-2 (C) 1975, or
  20. ***                             Blue Horizon: BH 3801 (C) 1969
  21. **/
  22. /***************************************************************************/
  23. /***************************************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <dos.h>
  27. #include <sys\types.h>
  28. #include <errno.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <direct.h>
  32.  
  33.  
  34. int puti(int, char *, char *);
  35. char *namecat(unsigned char *, unsigned char *);
  36. int delve(unsigned char *);
  37.  
  38. typedef unsigned char path[68];
  39.  
  40. char            version[]="\nTRUNK v0.96, 18 Feb 1988, by Mike O'Regan";
  41. int             dirs_found=0;
  42. int             files_found=0;
  43. unsigned int    srch_attrib=_A_NORMAL | _A_RDONLY | _A_SUBDIR;
  44. int             summary=0;
  45. int             print_dirs=1;
  46. int             print_files=0;
  47. int             force_lower=0;
  48. int             help=0;
  49. int             info=0;
  50. extern int      errno;
  51. extern char     *sys_errlist[];
  52.  
  53.  
  54.  
  55. /***************************************************************************/
  56. /***************************************************************************/
  57. /**
  58. *** main
  59. **/
  60. /***************************************************************************/
  61. /***************************************************************************/
  62.  
  63. void main(int argc, char *argv[])
  64.  
  65. {
  66. path            current_dir;
  67. unsigned char   *cwd_ptr=current_dir;
  68. path            search_dir;
  69. unsigned char   *search_ptr=search_dir;
  70. int             n;
  71.  
  72.  
  73. /**
  74. *** Get the current working directory for later.  If there is an error,
  75. *** cwd_ptr will equal NULL.  An error should only be caused by an
  76. *** illegally long path name.
  77. **/
  78. cwd_ptr=getcwd(current_dir, sizeof(path));
  79. if (cwd_ptr == NULL) {
  80.     puts(sys_errlist[errno]);
  81.     return;
  82.     }
  83.  
  84. /**
  85. *** Process any command line arguments that are flags.  The last argument
  86. *** is assumed to be the pathname.  Since the pathname is not required, the
  87. *** last argument may be a flag as well.
  88. **/
  89. if (argc > 1) {
  90.     for (n=1; n < argc; n++)    /* argv[0] always == TRUNK */
  91.         {
  92.         if (argv[n][0] == '/')
  93.             switch (argv[n][1]) {
  94.                 case 'y':   srch_attrib |= _A_SYSTEM;
  95.                 case 'h':   srch_attrib |= _A_HIDDEN;
  96.                             break;
  97.                 case 'o':   print_dirs=0;
  98.                             print_files=0;
  99.                 case 's':   summary=1;
  100.                             break;
  101.                 case 'F':   print_dirs=0;
  102.                             print_files=1;
  103.                             break;
  104.                 case 'l':   force_lower=1; break;
  105.                 case 'v':   puts(version);
  106.                             return;
  107.                 case '?':   help=1; break;
  108.                 case '$':   info=1; break;
  109.                 }
  110.         }   /* for (n=1; n < argc-1; n++) */
  111. /**
  112. *** If help was requested (through the -? flag or by TRUNK HELP), print
  113. *** a help message and quit.
  114. **/
  115.     if ( (help) || (argv[1][0] == '?') ) {
  116.         puts("\nTRUNK [?] [/?] [/h] [/y] [/F] [/s] [/o] [/l] [/v] [/$] [path]");
  117.         puts("    ?,/?: help -- display this message");
  118.         puts("    /h:   hidden -- include hidden directories/files in search");
  119.         puts("    /y    system -- include system files in search (activates /h)");
  120.         puts("    /F:   files -- display names of files found, not directories");
  121.         puts("    /s:   summary -- follow directory/file list with directory/file counts");
  122.         puts("    /o:   summary only -- display only a summary, no directory/file list");
  123.         puts("    /l:   lower case -- display directory/file names in lower case");
  124.         puts("    /v:   version -- display the current version of TRUNK");
  125.         puts("    /$:   display information about TRUNK");
  126.         puts("    path: path -- the path of the directory in which to start TRUNK");
  127.         return;
  128.         }
  129.     }   /* if (argc > 1) */
  130.  
  131. if (info) {
  132.     puts(version);
  133.     puts("\nThis version of TRUNK lies in the public domain and thus may be used by any");
  134.     puts("party for any purpose.  Send comments, bug reports, and Ronettes albums to:\n");
  135.     puts("Mike O'Regan\n2739 Kingston Dr.\nNorthbrook, IL  60062\n");
  136.     return;
  137.     }
  138.  
  139. /**
  140. *** If there are command line arguments, then the last one may be the
  141. *** path to search on.  If the last argument (argv[argc-1]) is not a flag,
  142. *** then it is assumed to be the search path.
  143. ***
  144. *** If there is a search path, but it is not a full path but merely a
  145. *** drive specifier (such as from 'TRUNK D:') which is not the current
  146. *** drive, then the operating system is called to change the current drive
  147. *** to the search drive, the current working directory of that drive is
  148. *** retrieved, and the current drive is reset to its original state.
  149. *** NOTE: For now a reference to another drive w/o path ('TRUNK 'A:') will
  150. ***     start *at the root* of the specified drive.
  151. ***
  152. *** If there is no search path in the command line, then the current
  153. *** working directory is used as the search path.
  154. **/
  155. if ( (argc > 1) && (argv[argc-1][0] != '/') ) {
  156.     strcpy(search_ptr,argv[argc-1]);
  157.     strupr(search_ptr);
  158.     if ( (search_ptr[1] == ':') && (search_ptr[2] == '\0') ) {
  159.         if (search_ptr[0] == cwd_ptr[0]) {
  160.             search_ptr=cwd_ptr;
  161.             }
  162.         else {
  163.             strcat(search_ptr,"\\");
  164.             }
  165.         }
  166.     }   /* if argc > 1 . . . */
  167. else {
  168.     search_ptr=cwd_ptr;
  169.     }
  170.  
  171. /**
  172. *** go for it
  173. **/
  174. if (force_lower)
  175.     strlwr(search_ptr);
  176. delve(search_ptr);
  177. if (summary) {
  178.     puti(dirs_found, "   "," directories found");
  179.     puti(files_found, ", containing ", " files\n");
  180.     }
  181. return;
  182. }
  183.  
  184.  
  185.  
  186. /***************************************************************************/
  187. /***************************************************************************/
  188. /**
  189. *** delve -- function that recursively steps down the directory structure
  190. *** of a disk, either printing directories/files or just watching them
  191. *** go by, according to the command line flags.
  192. **/
  193. /***************************************************************************/
  194. /***************************************************************************/
  195.  
  196. int delve(unsigned char *parent_ptr)
  197.  
  198. {
  199. struct find_t   my_dta;
  200. unsigned int    find_result;
  201. path            current_path;
  202. unsigned char   *current_end;
  203.  
  204.  
  205. /**
  206. *** Copy the path passed from above, and stick "\*.*" at the end of it.
  207. *** current_end ends up pointing to the spot at which to stick in file
  208. *** when propigate(sp?) names down the line (i.e. the 3rd char from the
  209. *** right in current_path).
  210. **/
  211. strcpy(current_path, parent_ptr);
  212. current_end=strchr(current_path,'\0');
  213. if (*(current_end-1) != '\\')
  214.     *(current_end++)='\\';
  215. strcpy(current_end,"*.*");
  216.  
  217. /**
  218. *** Find all the subdirectories in this directory.  If there are no files
  219. *** in this directory at all, then this must not be a valid directory, so
  220. *** the parent pathname is not printed.  The '.' and '..' directories
  221. *** are duly ignored.
  222. **/
  223. find_result=_dos_findfirst(current_path, srch_attrib, &my_dta);
  224. if (find_result == 0) {
  225.     if (print_dirs)
  226.         puts(parent_ptr);
  227.     ++dirs_found;
  228.     }
  229.  
  230. while (find_result == 0) {
  231.     if ( my_dta.name[0] != '.' ) {
  232.         namecat(current_end, my_dta.name);
  233.         if (force_lower)
  234.             strlwr(current_end);
  235.         if ( my_dta.attrib & _A_SUBDIR ) {
  236.             delve(current_path);
  237.             }
  238.         else {
  239.             ++files_found;
  240.             if (print_files)
  241.                 puts(current_path);
  242.             }
  243.         }   /* if my_dta.name[0] != '.' */
  244.     find_result=_dos_findnext(&my_dta);
  245.     }
  246. return(0);
  247. }
  248.  
  249.  
  250.  
  251. /***************************************************************************/
  252. /***************************************************************************/
  253. /**
  254. *** puti -- written to avoid using printf, which would add 2K to the EXE
  255. *** file size.  The three arguments consist of the integer to print, a
  256. *** pointer to a string to be printed before the integer, and a similar
  257. *** pointer to be printed after the integer.
  258. *** E.G.: puti(52,"There are "," cards in a deck.\n") yields
  259. ***     There are 52 cards in a deck.
  260. **/
  261. /***************************************************************************/
  262. /***************************************************************************/
  263.  
  264. int puti(int the_int, char *pre_str, char *post_str)
  265.  
  266. {
  267. char    number[7];
  268. int     n=0;
  269.  
  270.  
  271. itoa(the_int, number, 10);
  272. while (*pre_str != '\0')
  273.     putchar(*(pre_str++));
  274. while (number[n] != '\0')
  275.     putchar(number[n++]);
  276. while (*post_str != '\0')
  277.     putchar(*(post_str++));
  278. return(0);
  279. }
  280.  
  281.  
  282.  
  283. /***************************************************************************/
  284. /***************************************************************************/
  285. /**
  286. *** namecat -- function to take a filename from a dta--which is padded with
  287. *** spaces--and turn it into a string, which is placed at *target_ptr.
  288. **/
  289. /***************************************************************************/
  290. /***************************************************************************/
  291.  
  292. char *namecat(unsigned char *target_ptr, unsigned char *dta_name_ptr)
  293.  
  294. {
  295. unsigned char   *dest_ptr=target_ptr;
  296. unsigned char   ch;
  297.  
  298.  
  299. if (*dta_name_ptr != '\0')      /* properly handle *dta_name_ptr=='\0' */
  300.     while ( (ch=*(dta_name_ptr++)) != '\0') {
  301.         if (ch != ' ')
  302.             *(dest_ptr++)=ch;
  303.         }
  304. *dest_ptr='\0';
  305. return(target_ptr);
  306. }
  307.